﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Majoopic.Utility
{
    /// <summary>
    /// Utility to load the factory from different assembly
    /// </summary>
    public static class FactoryLoadUtility
    {
        /// <summary>
        /// Load an assembly by his name
        /// </summary>
        /// <param name="assemblyName">Name of the assembly</param>
        /// <returns>The object assembly or throw an exception if the assembly not found</returns>
        public static Assembly LoadAssembly(string assemblyName)
        {
            if (string.IsNullOrWhiteSpace(assemblyName))
            {
                throw new ArgumentNullException("assemblyName");
            }
            if (assemblyName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) == false)
            {
                throw new ArgumentException("Invalid assembly name", "assemblyName");
            }
            return Assembly.LoadFrom(assemblyName);
        }

        /// <summary>
        /// Load the factory from the assembly
        /// </summary>
        /// <param name="assemblyName">Name of the assembly</param>
        /// <param name="className">the entire classname of the factory (with the namespace)</param>
        /// <returns>An instance of the factory</returns>
        public static T LoadFactory<T>(string assemblyName, string className) where T : class
        {
            if (string.IsNullOrWhiteSpace(className))
            {                
                // without classname we load the first factory found
                return LoadFactory<T>(assemblyName);
            }
            if (assemblyName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) == false)
            {
                throw new ArgumentException("Invalid assembly name", "assemblyName");
            }

            Assembly assembly = LoadAssembly(assemblyName);
            Type factoryType = assembly.GetType(className);
            if (factoryType == null || factoryType.IsSubclassOf(typeof(T)) == false)
            {
                throw new Exception(String.Format("The className {0} in the assembly {1} is not found or isn't the type MajoopicAbstractFactory", className, assemblyName));
            }

            return (T)Activator.CreateInstance(factoryType);
        }

        /// <summary>
        /// Load the first factory found in the assembly
        /// </summary>
        /// <param name="assemblyName">Name of the assembly</param>
        /// <returns>An instance of the factory</returns>
        public static T LoadFactory<T>(string assemblyName) where T : class
        {
            Assembly assembly = LoadAssembly(assemblyName);
            Type factoryType = assembly.GetTypes().First(x => x.IsSubclassOf(typeof(T)));
            return (T)Activator.CreateInstance(factoryType);
        }
    }
}
